package com.eatpoint.plugins;

import android.Manifest;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.TextView;

import com.eatpoint.plugins.api.ApiResult;
import com.eatpoint.plugins.api.ApiService;
import com.eatpoint.plugins.floatwindow.FloatWindow;
import com.eatpoint.plugins.floatwindow.IFloatWindow;
import com.eatpoint.plugins.floatwindow.MoveType;
import com.eatpoint.plugins.floatwindow.PermissionListener;
import com.eatpoint.plugins.floatwindow.Screen;
import com.eatpoint.plugins.floatwindow.ViewStateListener;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import static android.app.Activity.RESULT_OK;

/**
 * This class echoes a string called from JavaScript.
 */
public class CallPhoneFloatWindow extends CordovaPlugin {

    private static final String TAG = "FloatWindow";
    private static final String TAG_MIN = "FloatWindow_min";
    private static final String TAG_OPEN = "FloatWindow_open";
    private static final int FLAG_TIMEOUT = 30 * 1000;
    private static final int FLAG_MAX_NUM = 3;

    private static String baseUrl = "https://foo.baojunev.com/mock/122/";
    private static String accessToken = "";

    private UserEntity userEntity = new UserEntity();

    private FakeR fakeR;
    private Retrofit retrofit;
    private boolean isFirstListener = true;
    private long queryTime = 0;
    private int queryNum = 0;

    private Handler handler = new Handler();

    @Override
    public void onStart() {
        super.onStart();
        fakeR = new FakeR(cordova.getActivity());
    }

    @Override
    public boolean execute(String action, String rawArgs, CallbackContext callbackContext) {
        fakeR = new FakeR(cordova.getActivity());
        if (action.equals("showFW")) {
            cordova.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    userEntity = new UserEntity(rawArgs);
                    showFW(userEntity, callbackContext);
                }
            });
            return true;
        } else if (action.equals("startCallListener")) {
            cordova.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    checkPermissions();
                    callbackContext.success();
                }
            });
            return true;
        } else if (action.equals("setNetwork")) {
            cordova.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    initNetwork(rawArgs);
                }
            });
            return true;
        }
        return false;
    }

    public void initNetwork(String json) {
        String jsonBaseUrl = "";
        try {
            JSONObject jsonObject = new JSONObject(json);
            if (jsonObject.has("accessToken"))
                accessToken = jsonObject.getString("accessToken");
            if (jsonObject.has("baseUrl"))
                jsonBaseUrl = jsonObject.getString("baseUrl");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        if (!baseUrl.equals(jsonBaseUrl) && !TextUtils.isEmpty(jsonBaseUrl)) {
            baseUrl = jsonBaseUrl;
            retrofit = null;
        }
    }

    public void ShowFW(UserEntity userEntity) {
        showFW(userEntity, null);
    }

    private void showFW(UserEntity userEntity, CallbackContext callbackContext) {

        if (FloatWindow.get(TAG_MIN) == null) {
            createFloatWindowMin();
        }
        showOneFloatWindow(true);
        TextView tx = Objects.requireNonNull(FloatWindow.get(TAG_MIN)).getView().findViewById(fakeR.getId("id", "tx_info"));
        tx.setText(String.format("%s\n%s", userEntity.getCustomerName(), userEntity.getMobilePhone()));
        if (callbackContext != null) {
            callbackContext.success("success");
        }
    }

    private void createFloatWindowMin() {

        View view = LayoutInflater.from(this.cordova.getContext()).inflate(fakeR.getId("layout", "view_float_window"), null);
        view.findViewById(fakeR.getId("id", "btn_open")).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                createFloatWindowOpen(userEntity);
                showOneFloatWindow(false);
            }
        });
        view.findViewById(fakeR.getId("id", "btn_exit")).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Objects.requireNonNull(FloatWindow.get(TAG_MIN)).hide();
            }
        });

        FloatWindow
                .with(this.cordova.getActivity().getApplicationContext())
                .setTag(TAG_MIN)
                .setView(view)
                .setWidth(Screen.width, 0.45f) //设置悬浮控件宽高
                .setHeight(Screen.width, 0.35f)
                .setX(Screen.width, 0.55f)
                .setY(Screen.height, 0.05f)
                .setMoveType(MoveType.slide, 0, 0)
                .setMoveStyle(500, new BounceInterpolator())
                .setFilter(false)
                .setViewStateListener(mViewStateListener)
                .setPermissionListener(mPermissionListener)
                .setDesktopShow(true)
                .build();
    }

    private void createFloatWindowOpen(UserEntity userEntity) {

        View view;
        if (FloatWindow.get(TAG_OPEN) == null) {
            view = LayoutInflater.from(this.cordova.getContext()).inflate(fakeR.getId("layout", "view_float_window_open"), null);
            int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            view.measure(w, h);
            int height = view.getMeasuredHeight();

            FloatWindow
                    .with(this.cordova.getActivity().getApplicationContext())
                    .setTag(TAG_OPEN)
                    .setView(view)
                    .setWidth(Screen.width, 0.9f) //设置悬浮控件宽高
                    .setHeight(height)
                    .setX(Screen.width, 0.05f)
                    .setY(Screen.height, 0.05f)
                    .setMoveType(MoveType.inactive)
                    .setViewStateListener(mViewStateListener)
                    .setPermissionListener(mPermissionListener)
                    .setDesktopShow(true)
                    .build();

            TextView btnClose = view.findViewById(fakeR.getId("id", "btn_close"));
            btnClose.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    showOneFloatWindow(true);
                }
            });
        }

        view = Objects.requireNonNull(FloatWindow.get(TAG_OPEN)).getView();
        TextView txName = view.findViewById(fakeR.getId("id", "tx_name"));
        TextView txSexAndAge = view.findViewById(fakeR.getId("id", "tx_sex_and_age"));
        TextView txPhone = view.findViewById(fakeR.getId("id", "tx_phone"));
        TextView txConsultant = view.findViewById(fakeR.getId("id", "tx_consultant"));
        TextView txCreateTime = view.findViewById(fakeR.getId("id", "tx_create_time"));
        TextView txLevel = view.findViewById(fakeR.getId("id", "tx_level"));
        TextView txCustomerSource = view.findViewById(fakeR.getId("id", "tx_customer_source"));
        TextView txCarModel = view.findViewById(fakeR.getId("id", "tx_car_model"));

        txName.setText(userEntity.getCustomerName());
        txPhone.setText(userEntity.getMobilePhone());
        txLevel.setText(userEntity.getIntentLevel());
        txCarModel.setText(userEntity.getModelName());
        if (userEntity.getAge() == 0) {
            txSexAndAge.setText(userEntity.getGender());
        } else {
            txSexAndAge.setText(String.format(Locale.CHINA, "%s | %d岁", userEntity.getGender(), userEntity.getAge()));
        }
        txConsultant.setText(userEntity.getConsultantName());
        txCreateTime.setText(userEntity.getCreatedTime());
        txCustomerSource.setText(userEntity.getSource());

    }

    private void showOneFloatWindow(boolean isMin) {
        IFloatWindow min = FloatWindow.get(TAG_MIN);
        IFloatWindow open = FloatWindow.get(TAG_OPEN);
        if (isMin) {
            if (min != null) min.show();
            if (open != null) open.hide();
        } else {
            if (min != null) min.hide();
            if (open != null) open.show();
        }
    }

    private PermissionListener mPermissionListener = new PermissionListener() {
        @Override
        public void onSuccess() {
            Log.d(TAG, "onSuccess");
        }

        @Override
        public void onFail() {
            Log.d(TAG, "onFail");
        }
    };

    private ViewStateListener mViewStateListener = new ViewStateListener() {
        @Override
        public void onPositionUpdate(int x, int y) {
            Log.d(TAG, "onPositionUpdate: x=" + x + " y=" + y);
        }

        @Override
        public void onShow() {
            Log.d(TAG, "onShow");
        }

        @Override
        public void onHide() {
            Log.d(TAG, "onHide");
        }

        @Override
        public void onDismiss() {
            Log.d(TAG, "onDismiss");
        }

        @Override
        public void onMoveAnimStart() {
            Log.d(TAG, "onMoveAnimStart");
        }

        @Override
        public void onMoveAnimEnd() {
            Log.d(TAG, "onMoveAnimEnd");
        }

        @Override
        public void onBackToDesktop() {
            Log.d(TAG, "onBackToDesktop");
        }
    };

    private Retrofit getRetrofit() {
        if (retrofit == null) {
            synchronized (CallPhoneFloatWindow.class) {
                retrofit = new Retrofit.Builder()
                        .baseUrl(baseUrl)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
            }
        }
        return retrofit;
    }

    private void needQuery(String phone) {
        if (queryNum < FLAG_MAX_NUM && System.currentTimeMillis() - queryTime < FLAG_TIMEOUT) {
            queryNum++;
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    queryUserInfo(phone);
                }
            }, 3000);
        }
    }

    private void queryUserInfo(final String phone) {

        if (TextUtils.isEmpty(accessToken)) {
            Log.e(TAG, "accessToken is Empty!!!");
            return;
        }
        ApiService apiService = getRetrofit().create(ApiService.class);
        Call<ApiResult<UserEntity>> call = apiService.getUserInfo(accessToken, phone);
        call.enqueue(new Callback<ApiResult<UserEntity>>() {
            @Override
            public void onResponse(Call<ApiResult<UserEntity>> call, Response<ApiResult<UserEntity>> response) {
                if (response.isSuccessful() && response.body() != null && response.body().getData() != null) {
                    if (response.body().getCode() == 200) {
                        userEntity = response.body().getData();
                        ShowFW(userEntity);
                    } else {
                        Log.d(TAG, "onResponse: " + response.body());
                    }
                } else {
                    needQuery(phone);
                }

            }

            @Override
            public void onFailure(Call<ApiResult<UserEntity>> call, Throwable t) {
                Log.d(TAG, t.toString());
                needQuery(phone);
            }
        });
    }

    /**
     * 获取来电监听权限
     */
    private void checkPermissions() {
        String[] permissions = {Manifest.permission.READ_CALL_LOG, Manifest.permission.READ_PHONE_STATE};
        List<String> permissionDeniedList = new ArrayList<>();
        for (String permission : permissions) {
            int permissionCheck = ContextCompat.checkSelfPermission(cordova.getContext(), permission);
            if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                startListener();
            } else {
                permissionDeniedList.add(permission);
            }
        }
        if (!permissionDeniedList.isEmpty()) {
            String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
            ActivityCompat.requestPermissions(cordova.getActivity(), deniedPermissions, 211);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if (requestCode == 211 && resultCode == RESULT_OK) {
            startListener();
        }
    }

    private void startListener() {
        if (isFirstListener) {
            isFirstListener = false;
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
            intentFilter.setPriority(Integer.MAX_VALUE);
            cordova.getActivity().registerReceiver(new IncomingReceiver(), intentFilter);
        }
    }

    /**
     * 接收来电广播消息
     */
    public class IncomingReceiver extends BroadcastReceiver {

        private final static String TAG = "IncomingReceiver";
        private String phoneNumber = "";

        @Override
        public void onReceive(Context context, Intent intent) {

            // 如果是拨打电话
            if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
                //拨打电话会优先,收到此广播. 再收到 android.intent.action.PHONE_STATE 的 TelephonyManager.CALL_STATE_OFFHOOK 状态广播;
                String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
                Log.d(TAG, phoneNumber);//获取拨打的手机号码
            } else {
                // 如果是来电
                TelephonyManager tManager = (TelephonyManager) context
                        .getSystemService(Service.TELEPHONY_SERVICE);
                //电话的状态
                switch (tManager.getCallState()) {
                    case TelephonyManager.CALL_STATE_RINGING:
                        //等待接听状态
                        Log.d(TAG, "TelephonyManager.CALL_STATE_RINGING");
                        phoneNumber = intent.getStringExtra("incoming_number");
                        phoneNumber = numberTrim(phoneNumber);
                        queryTime = System.currentTimeMillis();
                        queryNum = 0;
                        queryUserInfo(phoneNumber);
                        break;
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        //接听状态
                        Log.d(TAG, "TelephonyManager.CALL_STATE_OFFHOOK");
                        break;
                    case TelephonyManager.CALL_STATE_IDLE:
                        //挂断状态
                        Log.d(TAG, "TelephonyManager.CALL_STATE_IDLE");
                        break;
                }
            }
        }

        /**
         * 电话号码处理
         *
         * @return
         */
        private String numberTrim(String phoneNumber) {
            if (phoneNumber != null && phoneNumber.startsWith("+86"))
                phoneNumber = phoneNumber.substring(3);
            return phoneNumber;
        }

    }

}


